<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch, defineAsyncComponent, shallowRef, markRaw } from 'vue'
import { weatherApi } from '@/api'
import { ElMessageBox, ElMessage } from 'element-plus'
import MenusAdd from './MenusAdd.vue'
import axios from 'axios'
import { useRouter, useRoute } from 'vue-router'
import { useCounterStore } from '@/stores/counter'
import { menuApi } from '@/assets/Axios/axiosH'

// Pinia
const counts = useCounterStore()
const router = useRouter()
const route = useRoute()

// 动态组件映射（Vite import）用于把后端 url 映射为真实组件
// 注意：路径匹配采用简单规则：优先精确匹配文件名（/views/.../xxx.vue -> url '/.../xxx'），其次尝试包含匹配
const viewModules = import.meta.glob('/src/views/**/*.vue')



function findViewComponentForUrl(url: string) {
  if (!url) return null
  const normRaw = url.startsWith('/') ? url.slice(1) : url
  const norm = normRaw.replace(/\.vue$/i, '')
  const normLower = norm.toLowerCase().replace(/[^a-z0-9]/g, '')

  // exact paths
  const exact = `/src/views/${norm}.vue`
  if (exact in viewModules) return viewModules[exact]
  const alt = `/src/views/SystemManagement/${norm}.vue`
  if (alt in viewModules) return viewModules[alt]

  // try exact filename match (case-insensitive)
  for (const key in viewModules) {
    const file = key.split('/').pop()!.replace(/\.vue$/i, '')
    const fileNorm = file.toLowerCase().replace(/[^a-z0-9]/g, '')
    if (fileNorm === normLower) return viewModules[key]
  }

  // try partial/token match (strip trailing s)
  const normTrim = normLower.replace(/s$/i, '')
  for (const key in viewModules) {
    const file = key.split('/').pop()!.replace(/\.vue$/i, '')
    const fileNorm = file.toLowerCase().replace(/[^a-z0-9]/g, '')
    if (fileNorm.includes(normTrim) || normTrim.includes(fileNorm)) return viewModules[key]
  }

  return null
}

// 把扁平列表按照 ParentID 组装为树（如果后端返回扁平）
function buildTreeFromFlat(list: any[]) {
  const map = new Map<number, any>()
  const roots: any[] = []
  list.forEach((it: any) => { map.set(it.id, { ...it, children: [] }) })
  list.forEach((it: any) => {
    const node = map.get(it.id)
    const pid = it.parentID ?? it.ParentID ?? 0
    if (pid && map.has(pid)) map.get(pid).children.push(node)
    else roots.push(node)
  })
  return roots
}

// 切换角色并尝试通知后端（若接口存在），然后重新加载菜单
async function switchRoleTo(roleId: number | string) {
  try {
    // 尝试调用后端切换角色接口（若不存在可忽略错误）
    await axios.post('/api/SystemManagement/SwitchRole', { roleId }).catch(() => null)
  } catch (_) { }
  // 重新拉取菜单
  await fetchMenus()
}

// 天气：头部展示当前城市实时天气
const weatherLoading = ref(true)
const weatherState = ref<any>(null)
async function loadWeather(location = 'beijing') {
  try {
    const r: any = await weatherApi.getNow({ location, language: 'zh-Hans', unit: 'c' })
    const now = r?.results?.[0]?.now
    if (now) weatherState.value = { text: now.text, temperature: now.temperature }
  } catch (e) {
    // 忽略错误，头部保持简洁
  } finally { weatherLoading.value = false }
}

// 类型定义
interface ParentMenu { id: number; menuName: string }
interface ChildMenu { id: number; menuName: string; parentID?: number; url?: string; sortOrder?: number; isVisible?: number }
interface MenuData { parents: ParentMenu[]; children: Record<number, ChildMenu[]> }

// 菜单数据（从后端接口加载）
const menuData = reactive<MenuData>({ parents: [], children: {} })
const isLoading = ref(false)
const loadError = ref<string | null>(null)

// 配置菜单常量（用于在左侧固定插入“配置菜单”入口）
const CONFIG_PARENT_ID = -9999
const CONFIG_CHILD_ID = -9998
const CONFIG_PARENT = { id: CONFIG_PARENT_ID, menuName: '配置菜单', children: [{ id: CONFIG_CHILD_ID, menuName: '配置菜单管理', parentID: CONFIG_PARENT_ID, url: '/MenusAdd', sortOrder: 0, isVisible: 1 }] }

// 将后端 MenuDto 转为前端字段（递归）
function normalizeMenuDto(item: any): any {
  const converted: any = {
    id: item.Menuid ?? item.menuid ?? item.id ?? null,
    menuName: item.MenuName ?? item.menuName ?? item.name ?? '',
    parentID: item.ParentID ?? item.parentID ?? item.ParentId ?? item.parentId ?? null,
    url: item.Url ?? item.url ?? item.url1 ?? item.URL ?? '',
    sortOrder: item.SortOrder ?? item.sortOrder ?? item.sort ?? null,
    isVisible: item.IsVisible ?? item.isVisible ?? item.isShow ?? null
  }
  if (item.Children && Array.isArray(item.Children)) converted.children = item.Children.map(normalizeMenuDto)
  else if (item.children && Array.isArray(item.children)) converted.children = item.children.map(normalizeMenuDto)
  return converted
}

async function fetchMenus() {
  isLoading.value = true
  loadError.value = null
  try {
    const token = localStorage.getItem('token')
    const res = await axios.get('http://localhost:5216/api/SystemManagement/MenusShow', {
      headers: token ? { Authorization: `Bearer ${token}` } : undefined,
      timeout: 10000
    })
    const payload = res.data && (res.data.data ?? res.data)
    const normalizedRoots = (Array.isArray(payload) ? payload : (payload?.data ?? [])).map(normalizeMenuDto)

    // 过滤/排序并填充 menuData
    menuData.parents = []
    menuData.children = {}

    const visibleRoots = (normalizedRoots || [])
      .filter((r: any) => r.isVisible === 1)
      .sort((a: any, b: any) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0) || (a.id ?? 0) - (b.id ?? 0))

    visibleRoots.forEach((r: any) => {
      if (r.id == null) return
      menuData.parents.push({ id: r.id, menuName: r.menuName })
      const children = (r.children || [])
        .filter((c: any) => c.isVisible === 1)
        .sort((x: any, y: any) => (x.sortOrder ?? 0) - (y.sortOrder ?? 0) || (x.id ?? 0) - (y.id ?? 0))
      menuData.children[r.id] = children.map((c: any) => ({ id: c.id, menuName: c.menuName, parentID: c.parentID, url: c.url, sortOrder: c.sortOrder, isVisible: c.isVisible }))
    })

    // 插入配置菜单为第一个（若不存在）
    if (!menuData.parents.find(p => p.id === CONFIG_PARENT_ID)) {
      menuData.parents.unshift({ id: CONFIG_PARENT_ID, menuName: CONFIG_PARENT.menuName })
      menuData.children[CONFIG_PARENT_ID] = (CONFIG_PARENT.children || []).map((c: any) => ({ id: c.id, menuName: c.menuName, parentID: c.parentID, url: c.url, sortOrder: c.sortOrder, isVisible: c.isVisible }))
    }

    // 缓存菜单（供下次快速加载）
    try { localStorage.setItem('menu_cache', JSON.stringify(visibleRoots)) } catch (e) { }

    // 动态注册路由：优先映射真实组件，否则占位
    normalizedRoots.forEach((r: any) => {
      (r.children || []).forEach((c: any) => {
        const u = c.url || ''
        if (u && !/^https?:\/\//.test(u)) {
          const routeName = `menu-${c.id}`
          if (!router.hasRoute(routeName)) {
            // 尝试查找真实组件
            const loader = findViewComponentForUrl(u)
            if (loader) {
              // register as child of Main so router-view inside MainView renders it
              router.addRoute('Main', { path: u.startsWith('/') ? u.slice(1) : u, name: routeName, component: loader as any })
            } else {
              router.addRoute('Main', { path: u.startsWith('/') ? u.slice(1) : u, name: routeName, component: () => Promise.resolve({ template: `<div style="padding:20px">占位：${u}</div>` }) })
            }
          }
        }
      })
    })

    // 不自动选中任何父项；用户点击父项后才显示子菜单
    // 保持之前选中（如果存在且还有效），否则清空选择
    if (activeParentId.value != null && menuData.children[activeParentId.value]) {
      const firstChildren = menuData.children[activeParentId.value] || []
      activeChildId.value = firstChildren.length ? firstChildren[0].id : null
    } else {
      activeParentId.value = null
      activeChildId.value = null
    }
  } catch (err: any) {
    console.error('fetchMenus error', err)
    loadError.value = err?.message || '加载菜单失败'
  } finally { isLoading.value = false }
}

onMounted(() => {
  // 先加载缓存（若有），随后异步刷新
  loadMenuCache()
  // 先尝试还原上次选中（如果缓存菜单能提供），随后刷新菜单并再次尝试还原
  restoreSelection()
  fetchMenus().then(() => {
    // 当 menus 刷新完成后，尝试从持久化中恢复（以确保动态注册的路由/children 可用）
    restoreSelection()
  })
  // 加载实时天气
  loadWeather()
  console.log('MainView mounted')
})

// 缓存支持：优先从 localStorage 读取上次菜单，随后异步刷新
function loadMenuCache() {
  try {
    const raw = localStorage.getItem('menu_cache')
    if (!raw) return false
    const data = JSON.parse(raw)
    if (!Array.isArray(data)) return false
    // 构造 menuData 从已缓存的树
    menuData.parents = []
    menuData.children = {}
    data.forEach((r: any) => {
      if (r.id != null) {
        menuData.parents.push({ id: r.id, menuName: r.menuName })
        menuData.children[r.id] = (r.children || []).map((c: any) => ({ id: c.id, menuName: c.menuName, parentID: c.parentID, url: c.url, sortOrder: c.sortOrder, isVisible: c.isVisible }))
      }
    })
    // 如果缓存中没有我们的配置菜单，插入到第一位
    if (!menuData.parents.find(p => p.id === CONFIG_PARENT_ID)) {
      menuData.parents.unshift({ id: CONFIG_PARENT_ID, menuName: CONFIG_PARENT.menuName })
      menuData.children[CONFIG_PARENT_ID] = (CONFIG_PARENT.children || []).map((c: any) => ({ id: c.id, menuName: c.menuName, parentID: c.parentID, url: c.url, sortOrder: c.sortOrder, isVisible: c.isVisible }))
    }
    return true
  } catch (e) {
    return false
  }
}


// 高亮逻辑
function updateActiveByRoute() {
  const pList = menuData.parents || []
  for (const p of pList) {
    const children = menuData.children[p.id] || []
    const match = children.find((c) => c.url === route.path)
    if (match) { activeParentId.value = p.id; activeChildId.value = match.id; return }
  }
}
watch(() => route.path, updateActiveByRoute)

const activeParentId = ref<number | null>(null)
const activeChildId = ref<number | null>(null)
// 当前选中的子项对应的异步组件（用于右侧渲染，不改变 URL）
const selectedAsyncComponent = shallowRef<any>(null)

function loadSelectedComponentForChild(child: any) {
  if (!child || !child.url) { selectedAsyncComponent.value = null; return }
  if (/^https?:\/\//.test(child.url)) { selectedAsyncComponent.value = null; window.open(child.url, '_blank'); return }
  const loader = findViewComponentForUrl(child.url)
  if (loader) selectedAsyncComponent.value = markRaw(defineAsyncComponent(loader as any))
  else selectedAsyncComponent.value = markRaw({ template: `<div style="padding:1px">占位：${child.url}</div>` })
}

function saveSelection(child: any) {
  try {
    if (!child) { localStorage.removeItem('mainview_selected'); return }
    const payload = { parentID: child.parentID ?? null, childID: child.id ?? null, url: child.url ?? '' }
    localStorage.setItem('mainview_selected', JSON.stringify(payload))
  } catch (e) { }
}

function restoreSelection() {
  try {
    const raw = localStorage.getItem('mainview_selected')
    if (!raw) return
    const sel = JSON.parse(raw)
    if (!sel) return

    // 首先尝试通过父ID查找
    const pid = sel.parentID
    const cid = sel.childID
    if (pid != null && menuData.children[pid]) {
      const child = menuData.children[pid].find((c: any) => c.id === cid || c.url === sel.url)
      if (child) {
        activeParentId.value = pid
        activeChildId.value = child.id
        if (child.parentID === CONFIG_PARENT_ID && child.url === '/MenusAdd') selectedAsyncComponent.value = markRaw(MenusAdd)
        else loadSelectedComponentForChild(child)
        return
      }
    }

    // 回退到通过 url 或 id 在所有子项中查找
    for (const p of menuData.parents) {
      const children = menuData.children[p.id] || []
      const child = children.find((c: any) => c.id === cid || c.url === sel.url)
      if (child) {
        activeParentId.value = p.id
        activeChildId.value = child.id
        if (child.parentID === CONFIG_PARENT_ID && child.url === '/MenusAdd') selectedAsyncComponent.value = markRaw(MenusAdd)
        else loadSelectedComponentForChild(child)
        return
      }
    }
  } catch (e) { }
}
const currentChildren = computed<ChildMenu[]>(() => {
  return activeParentId.value != null ? (menuData.children[activeParentId.value] || []) : []
})
const currentDetail = computed(() => currentChildren.value.find(c => c.id === activeChildId.value) || { menuName: '', url: '' })

function selectParent(id: number) {
  activeParentId.value = id
  // 不自动选中任何子项，且清空右侧内容（刷新内容区为空）
  activeChildId.value = null
  selectedAsyncComponent.value = null
}

function onChildSelect(index: string) {
  // index could be url or menu-<id>
  const child = currentChildren.value.find(c => String(c.id) === index || c.url === index)
  if (child) {
    activeChildId.value = child.id
    // 不改变路由，只在右侧渲染对应组件
    // 如果是配置菜单的固定项，直接加载本地组件路径
    if (child.parentID === CONFIG_PARENT_ID && child.url === '/MenusAdd') {
      // 直接使用静态导入的组件以避免动态 chunk 延迟
      selectedAsyncComponent.value = MenusAdd
    } else {
      loadSelectedComponentForChild(child)
    }
    // persist selection so it survives full page reload
    saveSelection(child)
  }
}

function onParentMenuSelect(index: any) {
  const id = Number(index)
  if (!Number.isNaN(id)) selectParent(id)
}

async function deleteMenuById(id: number) {
  try {
    console.log('删除菜单请求', { id })
    await menuApi.deleteMenu(id)
    return true
  } catch (e: any) {
    console.error('deleteMenuById error', e)
    return false
  }
}

async function confirmDeleteParent(parentId: number) {
  try {
    await ElMessageBox.confirm('该删除无法恢复，确认删除吗？', '确认删除', { type: 'warning' })
  } catch (_) { return }
  const ok = await deleteMenuById(parentId)
  if (ok) {
    // 删除父项：移除父和其子，并刷新菜单数据以保持一致
    delete menuData.children[parentId]
    const idx = menuData.parents.findIndex(p => p.id === parentId)
    if (idx >= 0) menuData.parents.splice(idx, 1)
    // 重新拉取菜单缓存以同步后端状态
    fetchMenus()
    // 如果当前选中在被删除范围内，清空选择
    if (activeParentId.value === parentId) {
      activeParentId.value = null
      activeChildId.value = null
      selectedAsyncComponent.value = null
      saveSelection(null)
    }
    ElMessage({ message: '删除成功', type: 'success' })
  } else ElMessage({ message: '删除失败', type: 'error' })
}

async function confirmDeleteChild(child: any, parentId?: number) {
  try {
    await ElMessageBox.confirm('该删除无法恢复，确认删除吗？', '确认删除', { type: 'warning' })
  } catch (_) { return }
  const ok = await deleteMenuById(child.id)
  if (ok) {
    // 尝试按传入 parentId 删除，否则在所有父项中查找并删除
    let pid = parentId
    if (pid == null) {
      for (const p of menuData.parents) {
        const arr = menuData.children[p.id] || []
        const idx = arr.findIndex((x: any) => x.id === child.id)
        if (idx >= 0) {
          arr.splice(idx, 1)
          pid = p.id
          break
        }
      }
    } else {
      const arr = menuData.children[pid] || []
      const idx = arr.findIndex((x: any) => x.id === child.id)
      if (idx >= 0) arr.splice(idx, 1)
    }

    // 如果当前选中是该子项，清空选择
    if (activeChildId.value === child.id) {
      activeChildId.value = null
      selectedAsyncComponent.value = null
      saveSelection(null)
    }
    ElMessage({ message: '删除成功', type: 'success' })
    // 同步后端并刷新菜单
    fetchMenus()
  } else ElMessage({ message: '删除失败', type: 'error' })
}

function handleUserCommand(command: string) {
  if (command === 'logout') {
    localStorage.removeItem('token')
    counts.Logins.UserId = ''
    counts.Logins.Nickname = ''
    counts.Logins.RoleId = ''
    counts.Logins.RoleName = ''
    axios.defaults.headers.common['Authorization'] = ''
    router.push('/')
  } else if (command === 'profile') router.push('/profile')
}
</script>

<template>
  <div class="page-root">
    <!-- 顶部头部区域（Header）：显示应用标题、用户信息与操作 -->
    <header class="topbar header-top">
      <div class="top-left">
        <div class="app-title">TMS智慧物流管理系统</div>
      </div>
      <div class="top-right">
        <div class="weather" v-if="!weatherLoading && weatherState">
          <span class="wx-text">{{ weatherState.text }}</span>
          <span class="wx-temp">{{ weatherState.temperature }}°C</span>
        </div>
        <el-dropdown @command="handleUserCommand">
          <span class="el-dropdown-link user-area"><i class="el-icon-user"></i> <span class="user-name"
              style="color: black;">{{ counts.Logins.Nickname || '未登录' }}</span></span>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item command="profile">个人中心</el-dropdown-item>
              <el-dropdown-item command="logout">退出登录</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </header>

    <section class="content-area">
      <!-- 左侧父级菜单列（Parents）：列出所有父级菜单，点击后在中间显示子菜单 -->
      <aside class="col parents-col">
        <div class="brand-wrap">
          <div class="brand-logo"></div>
        </div>
        <el-menu class="parents-menu" :router="false" background-color="#1f2b33" text-color="#9fb0bd"
          active-text-color="#fff" @select="onParentMenuSelect">
          <el-menu-item v-for="p in menuData.parents" :key="p.id" :index="String(p.id)">
            <span class="menu-label">
              <span class="menu-name">{{ p.menuName }}</span>
              <span v-if="p.id !== CONFIG_PARENT_ID" class="delete-icon" @click.stop="confirmDeleteParent(p.id)"
                title="删除">×</span>
            </span>
          </el-menu-item>
        </el-menu>
      </aside>

      <!-- 中间子级菜单列（Children）：仅在选中父级且存在子项时显示 -->
      <aside v-if="currentChildren.length > 0" class="col children-col">
        <div class="menu-title"></div>
        <el-menu class="children-menu" :router="false" unique-opened background-color="#fff" text-color="#5a6b73"
          active-text-color="#409eff" :default-active="String(activeChildId)" @select="onChildSelect">
          <el-menu-item v-for="c in currentChildren" :key="c.id" :index="c.url || ('menu-' + c.id)">
            <span class="menu-label">
              <span class="menu-name">{{ c.menuName }}</span>
              <span v-if="!(c.parentID === CONFIG_PARENT_ID && c.id === CONFIG_CHILD_ID)" class="delete-icon"
                @click.stop="confirmDeleteChild(c, c.parentID)" title="删除">×</span>
            </span>
          </el-menu-item>
        </el-menu>
      </aside>

      <!-- 右侧主内容区（Main）：渲染所选子菜单对应的页面内容，独立滚动 -->
      <main class="col right-col">
        <div class="right-content">
          <component v-if="selectedAsyncComponent" :is="selectedAsyncComponent" />
          <div v-else class="placeholder"></div>
        </div>
      </main>
    </section>
  </div>
</template>

<style scoped>
#dify-chatbot-bubble-button {
  background-color: #1C64F2 !important;
}

#dify-chatbot-bubble-window {
  width: 24rem !important;
  height: 40rem !important;
}


/* 根容器：占满可视高度 */
.layout-root {
  height: 100%
}

/* 页面根容器：竖向布局，上部为头部，下部为内容 */
.page-root {
  /* 占满整个视窗，配合固定头部使用 */
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
}

/* 头部样式：绿色背景，左右布局 */
.header-top {
  background: #3aa57f;
  color: #fff;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 40px;
  /* 固定在顶部，不会影响内部列的独立滚动 */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
}

.weather {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-right: 16px;
}

.wx-text {
  font-size: 12px;
  opacity: .9;
}

.wx-temp {
  font-weight: 700;
}

/* 内容区：三列布局 */
.content-area {
  display: flex;
  gap: 0;
  padding: 0;
  /* 将内容区放在固定头部下方，并占满剩余高度 */
  margin-top: 50px;
  /* 与 .header-top 高度一致 */
  height: calc(100vh - 80px);
  background: #f3f6f8;
  overflow: hidden;
  /* 子列各自滚动 */
}

/* 列通用样式 */
.col {
  background: #fff;
  border-radius: 4px;
}

/* 左侧父级菜单列：窄列，深色背景 */
.parents-col {
  width: 130px;
  background: #1f2b33;
  color: #9fb0bd;
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* 允许子元素溢出并独立滚动 */
}

/* 中间子级菜单列：中等宽度 */
.children-col {
  width: 120px;
  color: #000000;
  display: flex;
  flex-direction: column;
}

/* 右侧内容列：自适应宽度，纵向布局 */
.right-col {
  margin-top: 20px;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}

/* 右侧内容容器：白底、圆角 */
.right-content {
  flex: 1 1 auto;
  background: #fff;
  border-radius: 0;
  padding: 0;
  overflow: auto;
}

/* 左中列的菜单区域独立滚动：brand-wrap 固定，菜单滚动 */
.parents-col .parents-menu {
  flex: 1 1 auto;
  overflow: auto;
  min-height: 0;
}

.children-col .children-menu {
  flex: 1 1 auto;
  overflow: auto;
  min-height: 0;
}

/* 将品牌区高度收敛，避免占用过多顶部空间 */
.brand-wrap {
  flex: 0 0 auto;
}

/* 右侧占位提示样式 */
.placeholder {
  padding: 20px;
  color: #666
}


/* 品牌区域间距 */
.brand-wrap {
  padding: 0
}

/* 品牌文字颜色与权重 */
.brand-logo {
  color: #fff;
  font-weight: 700
}

/* 图标菜单项居中 */
.icon-menu .el-menu-item {
  text-align: center;
  padding: 12px 0
}

/* 左侧菜单背景 */
.left-menu {
  background: #f6f8fb;
  border-right: 1px solid #e6eef3
}

/* 菜单标题样式 */
.menu-title {
  padding: 20px;
  font-weight: 700;
  color: #33414a
}

/* 菜单列表间距 */
.menu-list {
  padding-bottom: 0px
}

/* 子菜单标题行对齐 */
.menu-list .el-sub-menu__title {
  display: flex;
  align-items: center;
  gap: 5px
}

/* 菜单项内边距 */
.menu-list .el-menu-item {
  padding-left: 1px
}

/* 菜单选中高亮背景 */
.menu-list .el-menu-item.is-active {
  background: #eaf6ff
}

.menu-label {
  display: inline-flex;
  align-items: center;
  gap: 6px
}

.menu-name {
  display: inline-block
}

.delete-icon {
  font-size: 12px;
  color: #ff4d4f;
  visibility: hidden;
  cursor: pointer
}

.menu-label:hover .delete-icon {
  visibility: visible
}


/* 应用标题样式 */
.app-title {
  font-size: 16px;
  font-weight: 700
}

/* 用户区域样式 */
.user-area {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer
}



/* 统计卡片样式 */
.stat-card {
  text-align: center;
  padding: 24px
}
</style>
